﻿package cocoaas3.flash{

	import cocoaas3.*;
	import flash.events.*;
	import flash.display.*;
	import flash.geom.*;
	import jp.nium.core.debug.Logger;

	public class UIScrollView extends UIView {
		
		// original
		private var _contentSize:CGSize = new CGSize( 640, 640 )
		public function set contentSize( val:CGSize ):void{ _contentSize = val; }
		public function get contentSize():CGSize{ return _contentSize; }

		private var _dragging:Boolean = false;// ドラッグ中か？
		public function get dragging():Boolean{
			return _dragging;
		}
		public var decelerationRate:Number = 1.1;

		private var _backgroundColor:Object;
		override public function set backgroundColor( val:Object ):void{
			_backgroundColor = val;

			bgShape = new Shape();
			var g:Graphics = bgShape.graphics;
			if( val is uint ){
				g.beginFill( uint(val) );	// 面のスタイル設定
			}
			g.drawRect( 0, 0, this.frame.width, this.frame.height );
			this.addChild( bgShape );
			this.addChild( subviewContainer );
		}

		// custom
		private var bgShape:Shape;
		private var _mouseDownPosY:int = 0;// mouseDown した時のマウスの stageY
		private var _posYOnMouseDown:int = 0;// mouseDown した時の自身の y 座標
		private var _prevPosY:Number = 0;
		private var _speed:Number = 0;
		private var _isScrolling:Boolean = false;// スクロール中か？
		private var _hasMaskSet:Boolean = false;// マスクせっとした？
		private var _mouseMoveProcessed:Boolean = false;// 負荷軽減のため、1フレームに1回しかMouseMoveイベントを処理しないように判定するフラグ	
		private var previousMouseStagePoint:Point = new Point();
		private var mouseDown:Boolean = false;// UIScrollView上でマウス押したか？
		private var _tempRect:Rectangle;// subviewContainer の scrollRect 一時保持用
		private var _bottomPosY:int; // 一番下にスクロールしたときのscrollRectのy座標

		private var _onMoveUp_event:Event = new Event("onMoveUp");
		private var _onMoveDown_event:Event = new Event("onMoveDown");


		public function UIScrollView( frameSize:CGSize ){
			trace( "UIScrollView constructor" );
			this.frame = new CGRect( 0, 0, frameSize.width, frameSize.height );
			subviewContainer.scrollRect = new Rectangle( 0, 0, frameSize.width, frameSize.height );
			// subviewContainer に cacheAsBitmap、opaqueBackground すると遅くなるのでしません。
			// subviewContainer にふくめる UIView に対して適宜 cacheAsBitmap、opaqueBackground してください。
			_tempRect = subviewContainer.scrollRect;

			// Uタッチ判定用に、透明の背景を作る
			bgShape = new Shape();
			this.addChild( bgShape );


			// subviewContainer を全面に
			this.addChild( subviewContainer );
		}

		override internal function onAddedToStage(e:Event):void{
			trace( "UIScrollView onAddedToStage" );
			super.onAddedToStage( e );
			// 背景のサイズをフィット
			// background_mc内のShapeのサイズを変更しないと、MouseEvent.stageXYが正しく取れないので注意。
			//background_mc.getChildAt(0).width = contentSize.width;
			//background_mc.getChildAt(0).height = contentSize.height;
			this.addEventListener( Event.ENTER_FRAME, _loop );
			this.addEventListener( MouseEvent.MOUSE_DOWN, _onMouseDown );
			stage.addEventListener( MouseEvent.MOUSE_MOVE, _onMouseMove );
			stage.addEventListener( MouseEvent.MOUSE_UP, onStageMouseUp );
		}

		override internal function onRemovedFromStage(e:Event):void{
			trace( "UIScrollView onRemovedFromStage" );
			super.onRemovedFromStage( e );
			this.removeEventListener( Event.ENTER_FRAME, _loop );
			this.removeEventListener( MouseEvent.MOUSE_DOWN, _onMouseDown );
			stage.removeEventListener( MouseEvent.MOUSE_MOVE, _onMouseMove );
			stage.removeEventListener( MouseEvent.MOUSE_UP, onStageMouseUp );
		}



		private function _onMouseDown( e:MouseEvent ):void{
			_speed = 0;
			mouseDown = true;
			_mouseDownPosY = e.stageY;
			_posYOnMouseDown = _tempRect.y;
		}


		private function onStageMouseUp( e:MouseEvent ):void{
			//Logger.info( "UIScrollView ドラッグを終了しました。" );
			_dragging = false;
			mouseDown = false;
		}

		private function _onMouseMove( e:MouseEvent ):void{
			// 指移動スピードを求める
			if( mouseDown ){
				_speed = e.stageY - previousMouseStagePoint.y;
			}
			previousMouseStagePoint.x = e.stageX;
			previousMouseStagePoint.y = e.stageY;

			if( mouseDown == false ){
				return;
			}


			if( _mouseMoveProcessed ){
				return;
			}


			var gap:int = e.stageY - _mouseDownPosY;
			// タッチ後少しでも動いたら、ドラッグ中と判断する
			if( _dragging == false && (gap<0?-gap:gap) > 1 ){// 高速に絶対値を求める
				//Logger.info( "UIScrollView スクロール開始しました。" );
				_dragging = true;
				_isScrolling = true;
				this.mouseChildren = false;
			}

			// 領域外へスライドしようとしたときは抵抗を加える
			if( _tempRect.y < 0 ){
				_tempRect.y = (_posYOnMouseDown - gap)/2;
			} else if( _tempRect.y > _bottomPosY ){
				_tempRect.y = (_posYOnMouseDown - gap + _bottomPosY ) / 2;
			} else {
				_tempRect.y = _posYOnMouseDown - gap;
			}
			_mouseMoveProcessed = true;
			//Console.log( "_onMouseMove end" );
		}


		public function _loop( e ):void{
			// パフォーマンスチェック用コード
			//_tempRect.y++;
			//subviewContainer.scrollRect = _tempRect;
			//return;

			//Console.log( "_loop start" );
			calcBottomPosY();
			_mouseMoveProcessed = false;
			_speed /= this.decelerationRate;
			if( _dragging == false ){
				// 領域外でマウスを離した時のための計算
				if( _tempRect.y < 0 ){
					_speed = _tempRect.y / 4;
				} else if( _tempRect.y > _bottomPosY ){
					_speed = (_tempRect.y - _bottomPosY) / 4;
				}
				_tempRect.y -= _speed;
				if( (_speed<0?-_speed:_speed) < 1 ){// 高速に絶対値を求める
					_speed = 0;
				}
			}
			if( _speed == 0 && _isScrolling==true && _dragging==false ){
				//Logger.info( "UIScrollView スクロール終了しました。" );
				_isScrolling = false;
				this.mouseChildren = true;
			}

			// 慣性移動中もイベントを発行するため、mouseMoveではなくenterframeループでイベントを発行
			if( _tempRect.y > _prevPosY ){
				this.dispatchEvent( _onMoveUp_event );
			} else if( _tempRect.y < _prevPosY ){
				this.dispatchEvent( _onMoveDown_event );
			}

			_tempRect.y = Math.floor( _tempRect.y );
			_prevPosY = _tempRect.y;
			//Console.log( "_loop end" );
			//trace( c,  _tempRect );
			if( subviewContainer.scrollRect.equals(_tempRect)==false ){
				subviewContainer.scrollRect = _tempRect;
			}
		}


		// 一番下にスクロールしたときのy座標を求める
		private function calcBottomPosY():void{
			_bottomPosY = contentSize.height - this.frame.height;
			if( _bottomPosY < 0 ){
				_bottomPosY = 0;
			}
		}





	}
}